Scheme 语言足够用于产品开发

#Innolight #Lisp

过去十年,我一直尝试在产品环境中使用 Scheme 编程语言。关于 Scheme 的传说总是充满吸引力、矛盾且神秘。然而,尽管 Scheme 在学术界声名显赫,但我确信很少有人尝试在产品中使用它。因为我很少看到有关在产品开发中使用 Scheme 所遇到问题的讨论。大多数人只是在追随别人的观点,很少有人讨论实际问题以及如何解决这些问题。

我选择了 GNU Guile,同时也使用过其他 Scheme 实现。当然,我的经验有限,这并不意味着 GNU Guile 足够成熟可以取代 Python。我的观点不仅适用于 GNU Guile,也适用于其他 Scheme 实现。我推荐你了解 Chez Scheme、Racket、Chicken Scheme 等,看看 Scheme 社区在过去二十年的发展。

因此,这篇文章不会告诉你为什么要选择 Scheme 而不是 Python。不是这样的。本篇文章讨论的是,如果你已经注意到函数式编程的趋势,并希望了解一些知名的函数式编程语言,这篇文章可能会帮助你了解 Scheme 在产品中的强大之处。

老生常谈的问题:为什么要使用 Scheme?

关于这个问题有无数答案,我就不一一列举了。如果你对 Scheme 不熟悉,这里是一些你需要知道的点:

第一个幻觉:很难找到 Scheme 程序员

确实,直接招聘到专业的 Scheme 程序员是很难的,因为很少有人有在产品中使用 Scheme 的经验。

五年前,我第一次尝试组建 Scheme 团队时,我也担心这个问题。然而,两个月后,我意识到这根本不是问题。我们可以以低成本培养 Scheme 程序员。以下是我关于招聘的简短故事。

当时,我们用 C++14 进行系统编程,用 Scheme 进行业务逻辑脚本编写。因为担心难以招聘到 Scheme 程序员,我的想法是只考察候选人在 C++ 中对函数式编程的了解。如今,C++ 已经有许多函数式特性,因此 C++ 程序员对函数式编程有所了解是很正常的。

如果候选人足够优秀以通过我们的面试,我会在新人培训中教授他们《计算机程序的构造和解释》(SICP)。当然,SICP 对于新手来说是一本大书,所以我只挑选了前两章。“数据抽象”用于理解面向对象,“过程抽象”用于优化算法实现。而 SICP 中的“元语言抽象”和“机器抽象”部分被我们舍弃了,因为我们当时没有开发编译器业务(现在有了,这是另一个故事)。

培训持续了一个月。培训结束后,他们开始在产品中进行小规模的工作,如修复错误或实现小功能。SICP 不仅是一本书,它也是由深邃智慧设计的正规教育体系。我们可以利用这个体系,迅速完成培训,并在记忆犹新时将所学内容应用到日常工作中。

通过 SICP 教育体系,我们可以在短时间内培养出优秀的 Scheme 程序员。任何技术公司都有新人培训期,我们可以在一个月内完成。这是一个成本低廉且可行的方案。我们已经这样坚持了五年,一切顺利。

想想看,我们在这项培训上几乎没有花费任何费用,却能够在短时间内将 SICP 的知识转化为产品中的价值。

第二个幻觉:Scheme 不够快

这已经不再是事实了,你听说过 Chez Scheme 吗?

多年前,我还是研究生的时候,就对编程语言的速度着迷。

但当我成为一名专业开发者后,我意识到编程中至少有三种速度:

  1. 学习速度:从零基础学习一种语言有多容易?
  2. 开发速度:我们能否尽可能减少编码工作?
  3. 执行速度:程序执行速度有多快?

了解了这些,我突然明白了为什么 Ruby on Rails 在 Web 开发中如此受欢迎,尽管它被认为是一种“慢语言”。

如果只考虑执行速度,那么汇编甚至机器语言会是更好的选择。

第三个幻觉:生态系统是编程语言最重要的部分

我的朋友,请不要再相信这个假设了。在实际工作中,它并不完全正确。

如果你需要一个真实的故事,这里有一个:语言本身才是生态系统的基础。

Python 的生态系统只是为 Python 语言服务。Python 拥有庞大的生态系统是有历史原因的,但这并不意味着其他语言也需要一个同等规模的生态系统。

事实上,唯一真正的生态系统是 C 生态系统。动态语言的模块大多只是现有 C 库的绑定。

因此,如果一门语言有良好的 FFI(外部函数接口)支持,它就可以利用所有的 C 库。如今,人们可能更加关注分布式处理。分布式系统可以是异构的,因此我们不需要将所有内容都构建在一个生态系统中。

另一方面,一个大的生态系统可能包含大量的包,但这并不意味着这些包及其依赖项都是高质量并且维护良好的。我们不应该对生态系统盲目相信。

所以,让我打破这个幻觉:生态系统在某些情况下可能很重要,但它不是一门语言的最重要特性。当我们创建一门语言时,我们需要考虑它的范式、语法、表达能力以及优化成本。这些才是编程语言最重要的部分。

过去,一门编程语言通常由公司推动,人们没有理由在没有报酬的情况下为其生态系统做出贡献。因此,对于一个商业化的编程语言社区来说,生态系统非常重要,否则发展会很缓慢,投资也会浪费。而如今,编程语言主要由自由开源软件(FOSS)社区推动。在 FOSS 的力量下,生态系统自然会成长。一个有经验的开发者会更加担心语言的表达能力,因为这决定了你的编码效率。

缺点 1:Scheme 尚未准备好用于深度学习

如今,深度学习很热门。我想向你介绍 AISCM 项目,它是一个用 GNU Guile 编写的项目,使用 LLVM JIT 并基于 TensorFlow。它可以运行,非常酷,我也为它贡献了一些补丁。然而,我没有太多时间投入其中。所以,如果你希望认真地使用 Scheme 进行深度学习,我建议你为 AISCM 做出贡献。

警告:AISCM 中已经有一个中间代码库,它还支持 OpenCV 和 FFmpeg。感谢作者 Jan Wedekind。

至于其他 Scheme 实现的深度学习进展,我了解得较少,但这只是我的视野局限。

缺点 2:Scheme 社区是分散的

由于历史原因,Scheme 存在许多实现,但社区是分散的。如今,我们看到了希望。

首先,Scheme 的标准化在过去十年中取得了良好进展。R7RS 将 Scheme 分为“小语言”和“大语言”。在我看来,这是一个好步骤。因为它既保持了 Scheme 的简洁性,又提供了一种将 Scheme 转变为工业级库规范的方法。

我的业务依赖于 R7RS 小语言,它就像为我们的业务量身定制一样。我稍后会谈到这一点。

另一个希望是现代包管理器。

我选择的是 GNU Guix,一个用 GNU Guile 编写的函数式包管理器。大多数 GNU Guile 库都可以通过 GNU Guix 安装。包管理器创造了生态系统。在实践中,我们不会说“生态系统”,因为这是一个商业概念。GNU 是一个操作系统社区。

当然,Racket 和 Chicken Scheme 也有良好的包管理器,这帮助它们形成了良好的社区。

无论如何,一致的标准规范和优秀的包管理器可能会修复分散的社区,但这需要时间。

缺点 3:Scheme 并非纯函数式语言

函数式编程爱好者可能希望使用纯函数式编程语言,也就是没有副作用的语言。

是的,Scheme 不是纯函数式语言,它是一种多范式语言,而不仅仅是函数式编程语言。但它提供了其他纯函数式语言中可以找到的完整函数式特性。尽管 Scheme 存在副作用,但你可以决定何时以及如何使用它。我认为禁止人们使用副作用并不是一个好主意。人们应该有选择使用语言的自由。Scheme 提供了这种自由,这可能是好事,也可能是坏事。但无论如何,你有选择的权利。

优点 1:Scheme 适合 Web 开发

如今,大多数 GUI 程序都被 SaaS 取代了。这就是为什么我提到 Web 开发,而不是传统的 GUI 开发。

2013 年,我开始编写 GNU Artanis,这是一个基于 GNU Guile 的现代 Web 框架。当时,我只是想用 Scheme 来完成一些简单的 Web 案例。

我没想到 GNU Artanis 能够帮助我完成物流机器人系统中的工业级 SOA(面向服务的架构),但事实证明它可以做到。而现在,GNU Artanis 已不再是一个小型代码片段。它包含 URL 重映射、关系映射、HTML 模板、异步协程服务器核心,以及与现代 JavaScript 前端框架(如 React)的集成等。你可以在一分钟内构建自己的网站或服务。

Racket 和 Chicken Scheme 在 Web 开发方面也有很好的机会。在我开始编写 GNU Artanis 之前,我曾用 Chicken Scheme 进行 Web 编程。

优点 2:Scheme 成本低廉且值得投资

Scheme 已在学术界研究了几十年。从嵌入式系统到分布式服务器开发,有大量关于 Scheme 的论文展示了积极成果。

那么问题来了,对于这样一门优秀的语言,学习和使用它会有多难?这个问题在“第一个幻觉”部分已经回答了:

在实践中,我们几乎没有花费任何成本进行 Scheme 培训,并且通过 SICP 这一良好的教育体系,我们可以在短时间内将知识转化为产品价值。

零成本的故事是真实的,我们没有算上我的工资,因为我花在培训上的时间并不多。当然,我们会讨论编程问题,但大部分讨论围绕的是一般编程问题,而非 Scheme 特定问题。如果你学过 Scheme,你会明白团队成员完全可以自己流畅地编写 Scheme 代码。

成本如此之低,尝试一下毫无伤害。

优点 3:Scheme 为你节省编码时间

作为一个经验丰富的 C/C++ 程序员,我不得不说,在非系统编程部分,我们不应该浪费时间用 C/C++ 编码。业务逻辑可能会根据需求而变化。用 C/C++ 编写一切并不灵活。不要把时间浪费在重构和调试上。

Scheme 强大的表达能力可以帮助你减少编码工作。

但这取决于你如何使用它。

如果你期望有许多库来减少你的工作量,Scheme 可能不是最佳选择。通常,这种需求适合概念验证阶段。你可以选择 Python。

如果你在依赖 C/C++ 代码库的基础上使用 Scheme 进行脚本编写,这是一个不错的选择。Scheme 是极简主义的,很容易作为脚本语言嵌入到系统中。

优点 4:用真实的计算机科学知识打造团队

当你再次抱怨代码审查中的糟糕编码时,你是否意识到你从未给过你的团队成员一个机会,让他们掌握严肃编程所需的真实计算机科学知识?Scheme 可以提供这样的机会,并且易于学习,最终,它足够优秀可以用于产品。

明智地选择你的武器。而且,学习更多事物并不坏,保持多样性是有益的。